Skip to content

fix(tests): derive the retired-invocation guard's file list from git - #119

Merged
StackOverFlow11 merged 1 commit into
mainfrom
fix/retired-invocation-guard-scope
Jul 31, 2026
Merged

fix(tests): derive the retired-invocation guard's file list from git#119
StackOverFlow11 merged 1 commit into
mainfrom
fix/retired-invocation-guard-scope

Conversation

@StackOverFlow11

Copy link
Copy Markdown
Owner

mainpytest 是红的1 failed),而每个 worktree 里都是绿的。本 PR 修根因。

症状与机制

test_no_new_file_starts_instructing_people_to_run_a_retired_toolrepo.rglob("*")文件系统,排除表只有 ("docs/progress/", ".git/", "tests/")。于是它读进了 gitignored 的工作材料:

tmp/context/** 里存着评审用 git archive 导出的退役之前的仓库副本——其中每一处命名退役工具都是合法的。14 行这样的命中让 pytest 在主 checkout 上失败。

值得记的是那个不对称

worktree 结构性地缺少两个会打破这个守卫的目录:它没有 tmp/,而嵌套的 .claude/worktrees/ 只存在于主 checkout 之下。而 C6、D5、D6a 的每一次 gate 都跑在 worktree 里

守卫看不见会打破它的那个东西——从我们一贯运行它的地方看不见。

修法

文件清单从 git 派生:tracked ∪ untracked-not-ignored。

  • untracked-not-ignored 是刻意包含的:一个新写的文件正是这个守卫存在的理由,而它通常还没 staged。
  • gitignored 变成不可见,这是本意(它们不是代码库),这条限制现在写进了 docstring,与它此前就看不见的另一条(运行时拼出的调用串)并列。

先例就在仓库里:D6a 新加的 caller census 正是为同样两条理由从 git 派生,其 docstring 两条都写了。这个守卫比它早,还没学到那一课。

牙是验过的,不是假定的

mutation 结果
新增 untracked-not-ignored 文件命名退役工具
移除该文件 绿
新增 gitignored 文件命名退役工具 绿(按声明,刻意不可见)

Gates(主 checkout,就是此前会红的那个地方)

pytest -p no:warnings 2705 passed / 1 skipped(此前 1 failed)· ruff clean · phase0 锚 ic 0.9600 / annual 0.8408 · validate-config 32/32 · exec_baseline_freeze --verify 77/77 @ 45c14aa · 改动仅 tests/test_hand_anchor_record.py(+25/−3)

The guard walked the filesystem with rglob, so on the main checkout it
read gitignored working material: tmp/context/** holds `git archive`
exports of pre-retirement revisions, every one of which names the retired
tools legitimately. Fourteen such lines made `pytest` fail on main while
passing in every worktree.

That asymmetry is the part worth recording. A worktree structurally lacks
both of the directories that break this guard - it has no tmp/, and the
nested .claude/worktrees/ only exists under the main checkout - and every
gate run for C6, D5 and D6a was made inside a worktree. The guard could
not see the thing that breaks it from the place we always ran it.

Derive the list from git instead: tracked plus untracked-not-ignored.
Untracked-not-ignored is included deliberately, because a newly written
file is exactly the case this guard exists for and it is usually not
staged yet. Gitignored files become invisible, which is the intent - they
are not the codebase - and that limit is now stated in the docstring
alongside the other one it already cannot see, invocation strings composed
at runtime.

The precedent is in the repo: the caller census added in D6a derives from
git for these same two reasons, and its docstring names both. This guard
predates it and had not learned the lesson.

Teeth verified rather than assumed: a new untracked-not-ignored file
naming a retired invocation turns it red, removing it turns it green, and
a gitignored file leaves it green as documented.

Gates on the main checkout: 2705 passed / 1 skipped (was 1 failed), ruff
clean, phase0 anchor ic 0.9600 / annual 0.8408, 32/32 configs, frozen
baseline 77/77.
@StackOverFlow11
StackOverFlow11 merged commit 8aa11c1 into main Jul 31, 2026
@StackOverFlow11
StackOverFlow11 deleted the fix/retired-invocation-guard-scope branch July 31, 2026 20:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant